home *** CD-ROM | disk | FTP | other *** search
- /*
- * The original copyright owners of the accompanying source code files have
- * agreed to place such code into the public domain. Accordingly, anyone
- * who receives or obtains a copy of such source code is freely entitled to
- * reproduce, use and otherwise exploit such code (including the right to
- * make derivative works), at his/her own risk and expense, without any
- * obligation or liability to the original copyright owners.
- *
- * We would appreciate (but do not require) that the following message be
- * included in any derivative works:
- *
- * "Portions of this program were developed by Peter Broadwell, Rob Myers
- * and Robin Schaufler while working in Silicon Valley."
- *
- * The accompanying source code files and related documentation materials
- * are distributed on an "AS IS" basis, without any warranties or
- * guarantees of any kind. All implied warranties, including the implied
- * warranties of merchantability and of fitness for any particular purpose,
- * are expressly disclaimed.
- */
- #include <stdio.h>
- #include "gl.h"
- #include "class.h"
- #include "classIds.h"
- #include "selectors.h"
- #include "mbox.h"
- #include "geom.h"
- #include "voxel.h"
-
- #ifndef TRUE
- #define TRUE 1
- #endif
- #ifndef FALSE
- #define FALSE 0
- #endif
-
- typedef struct {
- int dim;
- int dir;
- } dimdir;
-
- extern class mboxClass;
-
- voxel protovox;
- mailbox fullVoxels = {
- &mboxClass, /* myClass */
- 0, 0, /* classFcns, nFcns */
- /* mailbox */
- 0, 0, /* *subscribers, *subscribedTo */
- };
-
- extern voxel *clone();
-
- char *dumpVoxel(), *voxtic();
-
- fcnTable voxelFcns[] = {
- DUMPVOX, dumpVoxel,
- DOIT, voxtic,
- EOTABLE
- };
-
- class voxelClass = {
- &mboxClass, /* super, really mailbox */
- voxelFcns, /* fcnTable */
- sizeof(voxel),
- VOXEL
- };
-
- voxel voxelTemplate = {
- &voxelClass, /* myClass */
- 0, 0, /* classFcns, nFcns */
- /* mailbox */
- 0, 0, /* *subscribers, *subscribedTo */
- /* voxel */
- 0, 0, /* dim[0] */
- 0, 0, /* dim[1] */
- 0, 0, /* dim[2] */
- 0, 0, 0, /* volume.orig */
- 0, 0, 0 /* volume.extent */
- };
-
- /*
- * these macros belong in geom.h.
- */
- #define max_x(cube) (cube.orig.x + cube.extent.x)
- #define max_y(cube) (cube.orig.y + cube.extent.y)
- #define max_z(cube) (cube.orig.z + cube.extent.z)
-
- #define half_up(num) (((num) + 1) / 2)
- #define in_interval(aval, orig, ext) \
- ((aval) >= (orig) && (aval) < ((orig) + (ext)))
- /* #define abs(val) ((val) >= 0 ? (val) : -(val)) */
-
- /*
- * link prevvox ----> nextvox along linkdim.
- */
- linkVoxels(prevvox, nextvox, linkdim)
- voxel *prevvox, *nextvox;
- int linkdim;
- {
- voxel *tmpvox = NULL;
- int curdim;
-
- nextvox->dim[linkdim][NEXT] = NULL;
- prevvox->dim[linkdim][NEXT] = (inst *)nextvox;
- nextvox->dim[linkdim][PREV] = (inst *)prevvox;
- /* fill in other dimensions */
- for(curdim = 0; curdim < NDIMENSIONS; curdim++) {
- if(curdim == linkdim)
- continue;
- if(tmpvox = (voxel *)prevvox->dim[curdim][NEXT]) {
- nextvox->dim[curdim][NEXT] = tmpvox->dim[linkdim][NEXT];
- if(tmpvox = (voxel *)tmpvox->dim[linkdim][NEXT]) {
- tmpvox->dim[curdim][PREV] = (inst *)nextvox;
- }
- } else {
- nextvox->dim[curdim][NEXT] = NULL;
- }
- if(tmpvox = (voxel *)prevvox->dim[curdim][PREV]) {
- nextvox->dim[curdim][PREV] = tmpvox->dim[linkdim][NEXT];
- if(tmpvox = (voxel *)tmpvox->dim[linkdim][NEXT]) {
- tmpvox->dim[curdim][NEXT] = (inst *)nextvox;
- }
- } else {
- nextvox->dim[curdim][PREV] = NULL;
- }
- }
- }
-
- /*
- * Make a line of voxels headed by vox, in VOX_X dimension,
- * totalling universe_volume.x. Return vox.
- */
- voxel *
- makeLine(vox, universe_volume)
- voxel *vox;
- point *universe_volume;
- {
- voxel *curvox = NULL, *newvox = NULL;
- point relpos;
-
- if(vox == NULL || universe_volume == NULL)
- return vox;
- for(curvox = vox;
- curvox &&
- half_up(universe_volume->x) > max_x(curvox->volume);
- curvox = (voxel *)curvox->dim[VOX_X][NEXT])
- {
- newvox = clone(curvox);
- newvox->volume.orig.x += curvox->volume.extent.x;
- linkVoxels(curvox, newvox, VOX_X);
- relpos = newvox->volume.orig;
-
- /*
- * eventually, constrain targs < (universe/2) to be 0
- * and subtract (universe/2) from other targs.
- */
- #define adj(targ,co) ((targ+(co)/2))
- relpos.x = adj(relpos.x, newvox->volume.extent.x);
- relpos.y = adj(relpos.y, newvox->volume.extent.y);
- relpos.z = adj(relpos.z, newvox->volume.extent.z);
- newvox->mbox.subscribers = NULL;
- newvox->mbox.subscribedTo = NULL;
- }
- return vox;
- }
-
- /*
- * Make a plane of voxels headed by vox, in VOX_X,VOX_Y dimensions,
- * totalling universe_volume.[x,y]. Return vox.
- */
- voxel *
- makePlane(vox, universe_volume)
- voxel *vox;
- point *universe_volume;
- {
- voxel *curvox = NULL, *newvox = NULL;
-
- if(vox == NULL || universe_volume == NULL)
- return vox;
- makeLine(vox, universe_volume);
- for(curvox = vox;
- curvox &&
- half_up(universe_volume->y) > max_y(curvox->volume);
- curvox = newvox)
- {
- newvox = clone(curvox);
- newvox->volume.orig.y += curvox->volume.extent.y;
- linkVoxels(curvox, newvox, VOX_Y);
- makeLine(newvox, universe_volume);
- }
- return vox;
- }
-
- /*
- * Make a space of voxels headed by vox, in VOX_X,VOX_Y,VOX_Z
- * dimensions, totalling universe_volume.[x,y,z]. Return vox.
- */
- voxel *
- makeSpace(vox, universe_volume)
- voxel *vox;
- point *universe_volume;
- {
- voxel *curvox = NULL, *newvox = NULL;
-
- if(vox == NULL || universe_volume == NULL)
- return vox;
- makePlane(vox, universe_volume);
- for(curvox = vox;
- curvox &&
- half_up(universe_volume->z) > max_z(curvox->volume);
- curvox = newvox)
- {
- newvox = clone(curvox);
- newvox->volume.orig.z += curvox->volume.extent.z;
- linkVoxels(curvox, newvox, VOX_Z);
- makePlane(newvox, universe_volume);
- }
- return vox;
- }
-
- compileVox()
- {
- makeobj(1027);
- fishColor(WHITE);
- pushmatrix();
- scale((float)protovox.volume.extent.x,
- (float)protovox.volume.extent.y,
- (float)protovox.volume.extent.z);
- movei(0,0,0);
- drawi(1,0,0);
- drawi(1,1,0);
- drawi(0,1,0);
- drawi(0,1,1);
- drawi(1,1,1);
- drawi(1,0,1);
- drawi(0,0,1);
- popmatrix();
- closeobj();
- }
-
- /*
- * The big bang creates the 3D universe of
- * voxels to fill universe_volume.
- * final universe may exceed universe_volume
- * by a fraction of a voxel.volume if
- * voxel_volume doesn't divide evenly into
- * universe_volume.
- */
- voxel *
- bigBang(universe_volume, voxel_volume)
- point *universe_volume, *voxel_volume;
- {
- voxel *vox, *clone();
-
- if(universe_volume == NULL || voxel_volume == NULL)
- return NULL;
- vox = clone(&voxelTemplate);
- vox->volume.extent = *voxel_volume;
- protovox = *vox; /* debugging */
- vox->volume.orig.x = -universe_volume->x / 2;
- vox->volume.orig.y = -universe_volume->y / 2;
- vox->volume.orig.z = -universe_volume->z / 2;
-
- /* for debugging */
- compileVox();
- Expand(&fullVoxels);
-
- makeSpace(vox, universe_volume);
- return vox;
- }
-
- char *
- voxtic(vox)
- voxel *vox;
- {
- return (char *)vox;
- }
-
- char *
- drawVoxel(vox)
- voxel *vox;
- {
- register subscr *entry = NULL;
- char tag[20], *tagp = tag;
-
- if(vox == NULL) {
- fprintf(stderr, "drawVoxel: voxel is NULL\n");
- return NULL;
- }
- if((entry = vox->mbox.subscribers) == NULL) {
- /* return NULL;
- /* */
- }
- pushmatrix();
- translate((float)vox->volume.orig.x,
- (float)vox->volume.orig.y,
- (float)vox->volume.orig.z);
- /*
- * counteract effect of rotating the fishbowl
- */
- rotate(-900, 'y');
- for(; entry; entry = entry->next) {
- if(entry->member && entry->member->myClass) {
- sprintf(tagp, "%d ", entry->member->myClass->classId);
- tagp += strlen(tagp);
- }
- }
- callobj(1027);
- cmovi(0,0,0);
- charstr(tag);
- popmatrix();
- return NULL;
- }
-
- char *
- dumpVoxel(vox)
- voxel *vox;
- {
- if(vox == NULL) {
- fprintf(stderr, "dumpVoxel: voxel is NULL\n");
- return NULL;
- }
- fprintf(stderr,"[%d,%d,%d]",
- vox->volume.orig.x,
- vox->volume.orig.y,
- vox->volume.orig.z);
- return NULL;
- }
-
- char *
- dumpLine(vox)
- voxel *vox;
- {
- voxel *curvox;
-
- if(vox == NULL) {
- fprintf(stderr, "dumpLine: voxel is NULL\n");
- return NULL;
- }
- for(curvox = vox; curvox; curvox = (voxel *)curvox->dim[VOX_X][NEXT]) {
- dumpVoxel(curvox);
- if(curvox->dim[VOX_X][NEXT] == NULL) {
- fprintf(stderr, "\n");
- } else if(((voxel *)curvox->dim[VOX_X][NEXT])->dim[VOX_X][PREV]
- != (inst *)curvox)
- {
- fprintf(stderr, ">");
- } else {
- fprintf(stderr, " ");
- }
- }
- return NULL;
- }
-
- char *
- dumpPlane(vox)
- voxel *vox;
- {
- voxel *curvox;
-
- if(vox == NULL) {
- fprintf(stderr, "dumpLine: voxel is NULL\n");
- return NULL;
- }
- for(curvox = vox; curvox; curvox = (voxel *)curvox->dim[VOX_Y][NEXT]) {
- dumpLine(curvox);
- }
- return NULL;
- }
-
- char *
- dumpSpace(vox)
- voxel *vox;
- {
- voxel *curvox;
-
- if(vox == NULL) {
- fprintf(stderr, "dumpLine: voxel is NULL\n");
- return NULL;
- }
- for(curvox = vox; curvox; curvox = (voxel *)curvox->dim[VOX_Z][NEXT]) {
- dumpPlane(curvox);
- if(curvox->dim[VOX_Z][NEXT])
- fprintf(stderr,"\n");
- else
- fprintf(stderr,"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
- }
- return NULL;
- }
-
- pointInCube(aCube, aPoint)
- cube *aCube;
- point *aPoint;
- {
- if(!aCube || !aPoint)
- return FALSE;
- return (in_interval(aPoint->x, aCube->orig.x, aCube->extent.x) &&
- in_interval(aPoint->y, aCube->orig.y, aCube->extent.y) &&
- in_interval(aPoint->z, aCube->orig.z, aCube->extent.z));
- }
-
- /*
- * Given a voxel and a point, find the voxel containing that point.
- * If pt is outside the universe, find the voxel nearest to it.
- */
- voxel *
- findvox(vox, pt)
- voxel *vox;
- point *pt;
- {
- int dir = STATION;
-
- if(pt->x < vox->volume.orig.x) {
- dir = PREV;
- } else if(pt->x >= vox->volume.orig.x + vox->volume.extent.x) {
- dir = NEXT;
- } else dir = STATION;
- if(dir != STATION) {
- for(; vox && vox->dim[VOX_X][dir];
- vox = (voxel *)vox->dim[VOX_X][dir]) {
- if(in_interval(pt->x, vox->volume.orig.x, vox->volume.extent.x))
- break;
- }
- }
- if(pt->y < vox->volume.orig.y) {
- dir = PREV;
- } else if(pt->y >= vox->volume.orig.y + vox->volume.extent.y) {
- dir = NEXT;
- } else dir = STATION;
- if(dir != STATION) {
- for(; vox && vox->dim[VOX_Y][dir];
- vox = (voxel *)vox->dim[VOX_Y][dir]) {
- if(in_interval(pt->y, vox->volume.orig.y, vox->volume.extent.y))
- break;
- }
- }
- if(pt->z < vox->volume.orig.z) {
- dir = PREV;
- } else if(pt->z >= vox->volume.orig.z + vox->volume.extent.z) {
- dir = NEXT;
- } else dir = STATION;
- if(dir != STATION) {
- for(; vox && vox->dim[VOX_Z][dir];
- vox = (voxel *)vox->dim[VOX_Z][dir]) {
- if(in_interval(pt->z, vox->volume.orig.z, vox->volume.extent.z))
- break;
- }
- }
- return vox;
- }
-
- /*
- * Unsubscribe from vox; find the voxel containing newpos;
- * subscribe to it, and return it.
- */
- voxel *
- newVoxPosition(vox, newpos, indiv)
- voxel *vox;
- point *newpos;
- inst *indiv;
- {
- voxel *newvox;
- subscr *entry, *findvars();
-
- if(!vox || !newpos || !indiv)
- return vox;
- entry = findvars(indiv, VOXEL);
- if(pointInCube(&vox->volume, newpos) && entry
- && entry->member == (inst *)vox) {
- return vox;
- }
- unsubscribe(vox, indiv);
- if(!vox->mbox.subscribers)
- unsubscribe(&fullVoxels, vox);
- if(newvox = findvox(vox, newpos)) {
- if(!newvox->mbox.subscribers)
- subscribe(&fullVoxels, newvox);
- subscribe(newvox, indiv);
- } else {
- fprintf(stderr, "newVoxPosition: can't find vox for [%d,%d,%d]\n",
- newpos->x, newpos->y, newpos->z);
- }
- return newvox;
- }
-
- /*
- * Do a turtle walk of the voxels starting at vox,
- * using path, calling doit(vox, arg) for each vox reached
- * by a lower case letter.
- */
- voxTurtle(vox, path, viewVector, doit, arg)
- voxel *vox;
- char *path;
- point *viewVector;
- int (*doit)();
- char *arg;
- {
- dimdir order[NDIMENSIONS];
- char *pp;
- int dim, dir, call_doit, halt_flag = 0;
-
- initOrder(order);
- getOrder(order, (int *)viewVector);
- for (pp = path; *pp; pp++) {
- switch(*pp) {
- case 'f':
- call_doit = TRUE;
- dim = order[2].dim;
- dir = order[2].dir;
- break;
- case 'b':
- call_doit = TRUE;
- dim = order[2].dim;
- dir = ~order[2].dir & 01;
- break;
- case 'l':
- call_doit = TRUE;
- dim = order[1].dim;
- dir = order[1].dir;
- break;
- case 'r':
- call_doit = TRUE;
- dim = order[1].dim;
- dir = ~order[1].dir & 01;
- break;
- case 'u':
- call_doit = TRUE;
- dim = order[0].dim;
- dir = order[0].dir;
- break;
- case 'd':
- call_doit = TRUE;
- dim = order[0].dim;
- dir = ~order[0].dir & 01;
- break;
- case 'F':
- call_doit = FALSE;
- dim = order[2].dim;
- dir = order[2].dir;
- break;
- case 'B':
- call_doit = FALSE;
- dim = order[2].dim;
- dir = ~order[2].dir & 01;
- break;
- case 'L':
- call_doit = FALSE;
- dim = order[1].dim;
- dir = order[1].dir;
- break;
- case 'R':
- call_doit = FALSE;
- dim = order[1].dim;
- dir = ~order[1].dir & 01;
- break;
- case 'U':
- call_doit = FALSE;
- dim = order[0].dim;
- dir = order[0].dir;
- break;
- case 'D':
- call_doit = FALSE;
- dim = order[0].dim;
- dir = ~order[0].dir & 01;
- break;
- default:
- call_doit = 2;
- break;
- }
- if (call_doit == 2)
- continue;
- vox = (voxel *)vox->dim[dim] [dir];
- if (!vox)
- break;
- if (call_doit)
- halt_flag = doit(vox, arg, pp);
- if (halt_flag)
- break;
- }
- }
-
- initOrder(order)
- dimdir *order;
- {
- int i;
-
- for(i = 0; i < NDIMENSIONS; i++) {
- order[i].dim = i;
- order[i].dir = NEXT;
- }
- }
-
- getOrder(order, viewVec)
- dimdir *order;
- int *viewVec /* an NDIMENSIONed vector */;
- {
- int i, j, tmp;
- /* sort */
- for(i = 0; i < NDIMENSIONS; i++) {
- for(j = i+1; j < NDIMENSIONS; j++) {
- if(abs(viewVec [order[j].dim]) < abs(viewVec [order[i].dim]))
- {
- tmp = order[i].dim;
- order[i].dim = order[j].dim;
- order[j].dim = tmp;
- }
- }
- /* get direction */
- order[i].dir = (viewVec[order[i].dim] <= 0);
- }
- }
-